﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;

namespace WZ.Utils.WebHttp
{
    public class HtmlFormContext
    {
        /// <summary>
        /// 匹配表单名称的正则
        /// </summary>
        private const string c_FormNameRegex1 = @"<form[^>]*?[nN][aA][mM][eE]=""(.*?)""[^>]*?>";
        private const string c_FormNameRegex2 = @"<form[^>]*?[nN][aA][mM][eE]=(.*?)\s[^>]*?>";
        private const string c_FormNameRegex3 = @"<form[^>]*?[nN][aA][mM][eE]='(.*?)'[^>]*?>";

        /// <summary>
        /// 匹配提交方式的正则
        /// </summary>
        private const string c_FormMethodRegex1 = @"<form[^>]*?[mM][eE][tT][hH][oO][dD]=""(.*?)""[^>]*?>";
        private const string c_FormMethodRegex2 = @"<form[^>]*?[mM][eE][tT][hH][oO][dD]=(.*?)\s[^>]*?>";
        private const string c_FormMethodRegex3 = @"<form[^>]*?[mM][eE][tT][hH][oO][dD]='(.*?)'[^>]*?>";

        /// <summary>
        /// 匹配提交地址的正则
        /// </summary>
        private const string c_FormActionRegex1 = @"<form[^>]*?[aA][cC][tT][iI][oO][nN]=""(.*?)""[^>]*?>";
        private const string c_FormActionRegex2 = @"<form[^>]*?[aA][cC][tT][iI][oO][nN]=(.*?)\s[^>]*?>";
        private const string c_FormActionRegex3 = @"<form[^>]*?[aA][cC][tT][iI][oO][nN]='(.*?)'[^>]*?>";

        /// <summary>
        /// 匹配Input参数集合的正则
        /// </summary>
        private const string c_FormInputRegex1 = @"<input[^>]*?[nN][aA][mM][eE]=""([^>]*?)""[^>]*?[vV][aA][lL][uU][eE]=""([^>]*?)""[^>]*?>";
        private const string c_FormInputRegex2 = @"<input[^>]*?[nN][aA][mM][eE]=""([^>]*?)""[^>]*?[vV][aA][lL][uU][eE]='([^>]*?)'[^>]*?>";
        private const string c_FormInputRegex3 = @"<input[^>]*?[nN][aA][mM][eE]=""([^>]*?)""[^>]*?[vV][aA][lL][uU][eE]=([^>^'^""]*?)\s[^>]*?>";
        private const string c_FormInputRegex4 = @"<input[^>]*?[nN][aA][mM][eE]='([^>]*?)'[^>]*?[vV][aA][lL][uU][eE]=""([^>]*?)""[^>]*?>";
        private const string c_FormInputRegex5 = @"<input[^>]*?[nN][aA][mM][eE]='([^>]*?)'[^>]*?[vV][aA][lL][uU][eE]='([^>]*?)'[^>]*?>";
        private const string c_FormInputRegex6 = @"<input[^>]*?[nN][aA][mM][eE]='([^>]*?)'[^>]*?[vV][aA][lL][uU][eE]=([^>^'^""]*?)\s[^>]*?>";
        private const string c_FormInputRegex7 = @"<input[^>]*?[nN][aA][mM][eE]=([^>^'^""]*?)\s[^>]*?[vV][aA][lL][uU][eE]=""([^>]*?)""[^>]*?>";
        private const string c_FormInputRegex8 = @"<input[^>]*?[nN][aA][mM][eE]=([^>^'^""]*?)\s[^>]*?[vV][aA][lL][uU][eE]='([^>]*?)'[^>]*?>";
        private const string c_FormInputRegex9 = @"<input[^>]*?[nN][aA][mM][eE]=([^>^'^""]*?)\s[^>]*?[vV][aA][lL][uU][eE]=([^>^'^""]*?)\s[^>]*?>";
        private const string c_FormInputRegex10 = @"<input[^>]*?[vV][aA][lL][uU][eE]=""([^>]*?)""[^>]*?[nN][aA][mM][eE]=""([^>]*?)""[^>]*?>";
        private const string c_FormInputRegex11 = @"<input[^>]*?[vV][aA][lL][uU][eE]=""([^>]*?)""[^>]*?[nN][aA][mM][eE]='([^>]*?)'[^>]*?>";
        private const string c_FormInputRegex12 = @"<input[^>]*?[vV][aA][lL][uU][eE]=""([^>]*?)""[^>]*?[nN][aA][mM][eE]=([^>^'^""]*?)\s[^>]*?>";
        private const string c_FormInputRegex13 = @"<input[^>]*?[vV][aA][lL][uU][eE]='([^>]*?)'[^>]*?[nN][aA][mM][eE]=""([^>]*?)""[^>]*?>";
        private const string c_FormInputRegex14 = @"<input[^>]*?[vV][aA][lL][uU][eE]='([^>]*?)'[^>]*?[nN][aA][mM][eE]='([^>]*?)'[^>]*?>";
        private const string c_FormInputRegex15 = @"<input[^>]*?[vV][aA][lL][uU][eE]='([^>]*?)'[^>]*?[nN][aA][mM][eE]=([^>^'^""]*?)\s[^>]*?>";
        private const string c_FormInputRegex16 = @"<input[^>]*?[vV][aA][lL][uU][eE]=([^>^'^""]*?)\s[^>]*?[nN][aA][mM][eE]=""([^>]*?)""[^>]*?>";
        private const string c_FormInputRegex17 = @"<input[^>]*?[vV][aA][lL][uU][eE]=([^>^'^""]*?)\s[^>]*?[nN][aA][mM][eE]='([^>]*?)'[^>]*?>";
        private const string c_FormInputRegex18 = @"<input[^>]*?[vV][aA][lL][uU][eE]=([^>^'^""]*?)\s[^>]*?[nN][aA][mM][eE]=([^>^'^""]*?)\s[^>]*?>";

        /// <summary>
        /// 表单html正文
        /// </summary>
        public String Html { get; set; }

        /// <summary>
        /// 响应中包含当前表单的请求Url地址
        /// </summary>
        public Uri RefererUrl { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="html"></param>
        public HtmlFormContext(String html)
        {
            Html = html;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="html"></param>
        /// <param name="referer"></param>
        public HtmlFormContext(String html, Uri referer)
        {
            Html = html;
            RefererUrl = referer;
        }

        /// <summary>
        /// 表单名称
        /// </summary>
        public String Name
        {
            get
            {
                String returnValue = String.Empty;

                returnValue = HtmlContext.MatchRegexResult(c_FormNameRegex1, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                returnValue = HtmlContext.MatchRegexResult(c_FormNameRegex2, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                returnValue = HtmlContext.MatchRegexResult(c_FormNameRegex3, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                return returnValue;
            }
        }

        /// <summary>
        /// 提交方式
        /// </summary>
        public String Method
        {
            get
            {
                String returnValue = "GET";

                returnValue = HtmlContext.MatchRegexResult(c_FormMethodRegex1, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                returnValue = HtmlContext.MatchRegexResult(c_FormMethodRegex2, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                returnValue = HtmlContext.MatchRegexResult(c_FormMethodRegex3, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                return returnValue.ToUpper(CultureInfo.CurrentCulture);
            }
        }

        /// <summary>
        /// 提交地址
        /// </summary>
        public String Action
        {
            get
            {
                String returnValue = String.Empty;

                returnValue = HtmlContext.MatchRegexResult(c_FormActionRegex1, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                returnValue = HtmlContext.MatchRegexResult(c_FormActionRegex2, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                returnValue = HtmlContext.MatchRegexResult(c_FormActionRegex3, Html);
                if (!String.IsNullOrEmpty(returnValue)) return returnValue;

                //如果匹配结果不为http开头的绝对路径，根据RefererUrl的信息将匹配结果组装成绝对路径，否则直接返回结果
                if (returnValue.StartsWith("http", StringComparison.OrdinalIgnoreCase) || RefererUrl == null) return returnValue;
                if (returnValue.StartsWith("/", StringComparison.OrdinalIgnoreCase))
                {
                    returnValue = RefererUrl.Scheme + "://" + RefererUrl.Authority + returnValue;
                }
                else
                {
                    string segment = "";
                    for (int i = 0; i < RefererUrl.Segments.Length - 1; i++)
                    {
                        segment += RefererUrl.Segments[i];
                    }
                    segment = segment = "/" + returnValue;
                    returnValue = RefererUrl.Scheme + "://" + RefererUrl.Authority + segment;
                }

                return returnValue;
            }
        }

        /// <summary>
        /// 参数列表
        /// </summary>
        public Dictionary<String, String> Params
        {
            get
            {
                Dictionary<String, String> returnValue = new Dictionary<String, String>();

                foreach (Match match in new Regex(c_FormInputRegex1).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex2).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex3).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex4).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex5).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex6).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex7).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex8).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex9).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$1"))) returnValue.Add(match.Result("$1"), match.Result("$2"));
                }

                foreach (Match match in new Regex(c_FormInputRegex10).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex11).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex12).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex13).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex14).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex15).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex16).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex17).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                foreach (Match match in new Regex(c_FormInputRegex18).Matches(Html))
                {
                    if (!returnValue.ContainsKey(match.Result("$2"))) returnValue.Add(match.Result("$2"), match.Result("$1"));
                }

                return returnValue;
            }
        }
    }
}
